import json
import os
import random
import string
import uuid
from io import BytesIO

import xlwt as xlwt
from PIL import Image, ImageFont, ImageDraw
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.db.models import Q
from django.http import JsonResponse, HttpResponse

from olivebranch.settings import HOST_NAME
from user.models import UserInfo, Team, TeamPhoto


class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(username=username) | Q(email=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None


class Users:
    @staticmethod
    def login(request):
        if request.method == "POST":
            data = request.POST
            # data = json.loads(request.body)
            username = data.get("username")
            password = data.get("password")
            print(username)
            if username is not None and password is not None:
                auth = authenticate(request, username=username, password=password)
                if auth:
                    userid = auth.id
                    login(request, auth)
                    userInfoObj = UserInfo.objects.filter(user_id=userid).first()
                    userInfoObj.save()
                    return JsonResponse({
                        "code": 0,
                        "data": {
                            "type": userInfoObj.type,
                            "userid": userid
                        }
                    })
                else:
                    return JsonResponse({
                        "code": 1,
                        "info": "认证失败"
                    })
            else:
                return JsonResponse({
                    "code": 2,
                    "info": "校验失败"
                })
        else:
            return JsonResponse({
                "code": 3,
                "info": "error method"
            })

    @staticmethod
    def logout(request):
        logout(request)
        return JsonResponse({
            "code": 0
        })

    @staticmethod
    def register(request):
        if request.method == "POST":
            # data = json.loads(request.body)
            data = request.POST
            username = data.get("username")
            password = data.get("password")
            type = data.get("type")
            email = data.get("email")

            tname = data.get("tname")
            twebsite = data.get("twebsite")
            tintro = data.get("tintro")
            temail = data.get("temail")

            user = User.objects.filter(username=username).first()
            if username is None or password is None or type is None:
                return JsonResponse({'code': 2, 'data': {'info': '校验失败'}})
            if user is not None:
                return JsonResponse({'code': 1, 'data': {'info': 'Username exists'}})
            try:
                user = User.objects.create_user(username=username, password=password, email=email)
                user.save()
                userInfoObj = UserInfo.objects.create(user=user, type=type)
                userInfoObj.save()
            except:
                user.delete()
                # UserInfo.objects.get(user__username=username).delete()
                return JsonResponse({"code": 1, "data": {"info": '注册失败'}})
            if type == '2':
                if tname is not None and Team.objects.filter(name=tname).first() is None:
                    newTeamObj = Team.objects.create(admin=user, website=twebsite, intro=tintro, email=temail,
                                                     name=tname)
                    newTeamObj.save()
                    userInfoObj.teamTo = newTeamObj
                    userInfoObj.save()
                    return JsonResponse({
                        "code": 0,
                        "data": {
                            "id": user.id,
                            "username": user.username,
                            "teamid": newTeamObj.id,
                            "teamname": newTeamObj.name
                        }
                    })
                else:
                    user.delete()
                    return JsonResponse({'code': 1, 'data': {'info': 'Teamname exists'}})
            return JsonResponse({
                "code": 0,
                "data": {
                    "id": user.id,
                    "username": user.username,
                }
            })
        else:
            return JsonResponse({
                "code": 3,
                "info": "error method"
            })

    @staticmethod
    def batchReg(request):
        if request.method == "POST":
            # data = json.loads(request.body)
            data = request.POST
            type = data.get("type")
            amount = int(data.get("amount"))
            pwdType = data.get("pwdType")
            teamID = data.get("teamID")
            usernamePrefix = data.get("prefix")

            failList = []
            successList = []

            for i in range(amount):
                username = usernamePrefix + "_" + str(i)
                password = ''
                if pwdType == 0:  # 随机生成密码
                    characters = string.digits + string.ascii_letters
                    password = password.join([random.choice(characters) for j in range(8)])
                elif pwdType == 1:  # 与用户名相同
                    password = username
                if User.objects.filter(username=username).first() is None:
                    user = User.objects.create_user(username=username, password=password)
                    user.save()
                    userInfoObj = UserInfo.objects.create(user=user, type=type)
                    if teamID is not None and type == 3:
                        userInfoObj.teamTo.id = teamID
                    userInfoObj.save()
                    successList.append({"username": username, "password": password})
                else:
                    failList.append({"username": username, "password": password})

            response = HttpResponse(content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = 'attachment;filename=BatchRegisterResult_' + usernamePrefix + '.xls'

            excel = xlwt.Workbook(encoding='utf-8')
            success = excel.add_sheet('success')
            fail = excel.add_sheet('fail')

            i = 0
            for successItem in successList:
                success.write(i, 0, successItem['username'])
                success.write(i, 1, successItem['password'])
                i += 1

            i = 0
            for failItem in failList:
                fail.write(i, 0, failItem['username'])
                fail.write(i, 1, failItem['password'])
                i += 1

            output = BytesIO()
            excel.save(output)
            output.seek(0)
            response.write(output.getvalue())
            return response
        else:
            return JsonResponse({
                "code": 3,
                "info": "error method"
            })

    @staticmethod
    def getInfo(request):
        if request.method == "POST":
            # data = json.loads(request.body)
            data = request.POST
            userid = data.get("id")
            user = User.objects.get(id=userid)
            userInfoObj = UserInfo.objects.get(user=user)
            if user is not None and UserInfo is not None:
                type = userInfoObj.type
                response = {
                    "code": 0,
                    "data": {
                        "userid": user.id,
                        "username": user.username,
                        "name": userInfoObj.name,
                        "email": user.email,
                        "nick": userInfoObj.nick,
                        "phone": userInfoObj.phone,
                        "avatar": HOST_NAME + "/media/" + userInfoObj.avatar.name,
                        "intro": userInfoObj.intro,
                        "type": userInfoObj.type,
                        "regTime": userInfoObj.regTime,
                        "status": userInfoObj.status,
                        "lastLogin": userInfoObj.lastLogin
                    }
                }
                if type == 1 or type == 0:  # 标准用户
                    return JsonResponse(response)
                elif type == 2:  # 团队管理员
                    response['data']['teamLogo'] = HOST_NAME + "/media/" + userInfoObj.teamTo.logo.name
                    response['data']['teamWeb'] = userInfoObj.teamTo.website
                    response['data']['teamName'] = userInfoObj.teamTo.name
                    return JsonResponse(response)
                elif type == 3:  # 团队成员
                    response['data']['teamLogo'] = userInfoObj.teamTo.logo.name
                    response['data']['teamWeb'] = userInfoObj.teamTo.website
                    response['data']['teamName'] = userInfoObj.teamTo.name
                    return JsonResponse(response)
            else:
                return JsonResponse({
                    "code": 1,
                    "info": "id不存在"
                })
        else:
            return JsonResponse({
                "code": 3,
                "info": "error method"
            })

    @staticmethod
    def modInfo(request):
        if request.method == 'POST':
            # data = json.loads(request.body)
            data = request.POST
            id = data.get("id")
            user = User.objects.get(id=id)
            if UserInfo.objects.filter(user_id=id).exists():
                userInfoObj = UserInfo.objects.get(user_id=id)
            else:
                return JsonResponse({
                    "error_code": 3,
                    "message": "profile not exist"
                })
            userInfoObj.phone = data.get("phone")
            userInfoObj.name = data.get("name")
            userInfoObj.nick = data.get("nick")
            userInfoObj.intro = data.get("intro")
            userInfoObj.save()
            user.email = data.get("email")
            user.save()
            return JsonResponse({
                "error_code": 0,
                "message": "修改成功！"
            })
        else:
            return JsonResponse({
                "code": 3,
                "info": "error method"
            })

    @staticmethod
    def uploadAvatar(request):
        if request.method == 'POST':
            id = request.POST.get('id')
            file = request.FILES.get('file')
            user = User.objects.get(id=id)
            if UserInfo.objects.filter(user_id=id).exists():
                userInfoObj = UserInfo.objects.get(user_id=id)
            else:
                return JsonResponse({
                    "error_code": 3,
                    "message": "profile not exist"
                })
            ext = os.path.splitext(file.name)[1]
            file.name = str(uuid.uuid4().hex + ext)
            userInfoObj.avatar = file
            userInfoObj.save()
            user.save()
            return JsonResponse({
                "error_code": 0,
                "message": "upload success"
            })
        else:
            return JsonResponse({
                "code": 3,
                "info": "error method"
            })

    @staticmethod
    def captcha(request):
        def get_random_color():
            return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)

        characters = string.digits + string.ascii_letters
        captchaLen = random.randint(4, 6)
        captchaStr = ''.join([random.choice(characters) for j in range(captchaLen)])
        font = ImageFont.truetype('arial.ttf', 30)
        width = (captchaLen + 1) * 40
        height = 40
        img_obj = Image.new('RGB', (width, height), get_random_color())
        draw_obj = ImageDraw.Draw(img_obj)
        for i in range(captchaLen):
            draw_obj.text((20 + 40 * i, random.choice([random.randint(0, 10), random.randint(-10, 0)])), captchaStr[i],
                          fill=get_random_color(), font=font)
        for i in range(random.randint(1, 6)):
            for j in range(i * 10):
                draw_obj.point((random.randint(0, width), random.randint(0, height)), fill=get_random_color())
            draw_obj.line((random.randint(0, width), random.randint(0, height), random.randint(0, width),
                           random.randint(0, height)), fill=get_random_color())
        with open(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/media/captcha/{}.png'.format(
                captchaStr), 'wb') as f:
            img_obj.save(f, format='png')
        return JsonResponse({
            "code": 0,
            "data": {
                "url": HOST_NAME + "/media" + '/captcha/{}.png'.format(captchaStr),
                "ans": captchaStr
            }
        })

    @staticmethod
    def teamInfo(request):
        if request.method == "POST":
            data = request.POST
            teamID = data.get("id")
            teamObj = Team.objects.get(id=teamID)
            if teamObj is None:
                return JsonResponse({"code": 1, "message": "team not exist"})
            return JsonResponse({
                "code": 0,
                "data": {
                    "id": teamObj.id,
                    "admin": teamObj.admin.id,
                    "website": teamObj.website,
                    "name": teamObj.name,
                    "intro": teamObj.intro,
                    "logo": HOST_NAME + "/media/" + teamObj.logo.name,
                    "email": teamObj.email,
                    "regTime": teamObj.regTime,
                }
            })

    @staticmethod
    def modTeamInfo(request):
        if request.method == "POST":
            data = request.POST
            teamID = data.get("id")
            teamObj = Team.objects.get(id=teamID)
            if teamObj is None:
                return JsonResponse({"code": 1, "message": "team not exist"})
            website = data.get("website")
            if website is not None:
                teamObj.website = website
            intro = data.get("intro")
            if intro is not None:
                teamObj.intro = intro
            email = data.get("email")
            if email is not None:
                teamObj.email = email
            logo = request.FILES.get('logo')
            if logo is not None:
                ext = os.path.splitext(logo.name)[1]
                logo.name = str(uuid.uuid4().hex + ext)
                teamObj.logo = logo
            name = data.get("name")
            if name is not None:
                teamObj.name = name
            teamObj.save()
            return JsonResponse({
                "code": 0,
                "info": "success"
            })

    @staticmethod
    def teamUploadPhoto(request):
        if request.method == "POST":
            data = request.POST
            teamID = data.get("id")
            teamObj = Team.objects.get(id=teamID)
            if teamObj is None:
                return JsonResponse({"code": 1, "message": "team not exist"})
            photo = request.FILES.get('photo')
            intro = data.get("intro")
            tpObj = TeamPhoto.objects.create(team_id=teamID, photoIntro=intro)
            tpObj.photo = photo
            tpObj.save()
            return JsonResponse({
                "code": 0,
                "info": "success"
            })

    @staticmethod
    def teamListPhoto(request):
        if request.method == "POST":
            data = request.POST
            teamID = data.get("id")
            teamObj = Team.objects.get(id=teamID)
            if teamObj is None:
                return JsonResponse({"code": 1, "message": "team not exist"})
            tpObjs = TeamPhoto.objects.filter(team_id=teamID)
            photoList = []
            for tpObj in tpObjs:
                photoList.append({"photo": HOST_NAME + "/media/" + tpObj.photo.name, "intro": tpObj.photoIntro})
            return JsonResponse({
                "code": 0,
                "date": {
                    "list": photoList
                }
            })

    @staticmethod
    def modPwd(request):
        if request.method == "POST":
            # data = json.loads(request.body)
            data = request.POST
            id = data.get("id")
            oldpassword = data.get("oldpass")
            newpassword = data.get("newpass")
            user = User.objects.get(id=id)
            if user is None:
                return JsonResponse({"code": 1, "message": "user not exist"})
            username = user.username
            if oldpassword is not None and newpassword is not None and type is not None:
                islogin = authenticate(request, username=username, password=oldpassword)
                if islogin is None:
                    return JsonResponse({
                        "code": 3,
                        "message": "error old password"
                    })
                user.set_password(newpassword)
                user.save()
                return JsonResponse({
                    "code": 0,
                    "message": "修改成功"
                })
            else:
                return JsonResponse({
                    "code": 2,
                    "message": "error parameters"
                })

    @staticmethod
    def listCourses(request):
        if request.method == "POST":
            # data = json.loads(request.body)
            data = request.POST
            id = data.get("id")
            user = User.objects.get(id=id)
            if user is None:
                return JsonResponse({"code": 1, "message": "user not exist"})
            userInfo = UserInfo.objects.get(user=user)
            courses = userInfo.courses.all()
            courseList = []
            for course in courses:
                courseList.append(course.id)
            return JsonResponse({
                "code": 0,
                "data": {
                    "courses": courseList
                }
            })
        else:
            return JsonResponse({
                "code": 2,
                "message": "error parameters"
            })

    @staticmethod
    def hasJoin(request):
        if request.method == "POST":
            # data = json.loads(request.body)
            data = request.POST
            id = data.get("id")
            courseid = int(data.get("courseid"))
            user = User.objects.get(id=id)
            if user is None:
                return JsonResponse({"code": 1, "message": "user not exist"})
            userInfo = UserInfo.objects.get(user=user)
            courses = userInfo.courses.filter(id=courseid)
            if courses is not None:
                return JsonResponse({
                    "code": 0,
                    "data": {
                        "status": 'true',
                    }
                })
            else:
                return JsonResponse({
                    "code": 1,
                    "data": {
                        "status": 'false',
                    }
                })
        else:
            return JsonResponse({
                "code": 2,
                "message": "error parameters"
            })
